#include "SCA830.h"
module SCA830SpiP
{
	provides interface SCA830Spi;
	provides interface Init;
	
	uses interface SpiPacket as SPI;
	uses interface Resource as SPIResource;
	uses interface GeneralIO as Enable;
	uses interface Leds;
	uses interface Timer<TMilli> as RearbitDelay;
}
implementation
{

	uint8_t state = STATE_IDLE;
	uint8_t regAddr;
	norace error_t result;
	norace sca_status_t scaStat;
	norace uint8_t regData;
	uint16_t longRegData;
	uint8_t spiTxBuf[3];
	uint8_t spiRxBuf[3];
	
	task void SignalDone()
	{
		if(state == STATE_READING)
		{
			signal SCA830Spi.GetRegisterDone(result, scaStat, regData);
		}
		else
		{
			signal SCA830Spi.SetRegisterDone(result, scaStat);
		}
		
		state = STATE_IDLE;
	}
	
	inline sca_status_t GetScaStatus(uint8_t data)
	{
		sca_status_t stat;
		
		stat.frameError = ((data & 0x40) > 0);
		stat.powerOnRst = ((data & 0x20) > 0);
		stat.selfTest = ((data & 0x10) > 0);
		stat.saturation = ((data & 0x08) > 0);
		stat.parity = ((data & 0x01) > 0);
		
		return stat;
	}
	
	inline uint8_t GetParity(uint8_t data)
	{
		return (uint8_t)(((data & 0xFE) % 2) & 0x01);
	}
	
	inline error_t GetRegister(uint8_t address)
	{
		spiTxBuf[0] = (uint8_t)(((address & 0x3F) << 2) | (0 << 1) | GetParity(address));
		spiTxBuf[1] = 0;
		
		call Enable.clr();
		
		return call SPI.send(&spiTxBuf[0], &spiRxBuf[0], 2);
	}
	
	inline error_t SetRegister(uint8_t address, uint8_t data)
	{
		spiTxBuf[0] = (uint8_t)(((address & 0x3F) << 2) | (1 << 1) | GetParity(address));
		spiTxBuf[1] = data;
		
		call Enable.clr();
		
		return call SPI.send(&spiTxBuf[0], &spiRxBuf[0], 2);
	}
	
	command error_t Init.init()
	{
		call Enable.makeOutput();
		call Enable.set();
		
		state = STATE_IDLE;
		
		return SUCCESS;
	}
	
	command error_t SCA830Spi.GetRegister(uint8_t address)
	{
		atomic if(state == STATE_IDLE)
		{
			state = STATE_READING;
			regAddr = address;
			
			call RearbitDelay.startOneShot(1);
			return SUCCESS;
			
		}
		else return EBUSY;
	}

	command error_t SCA830Spi.SetRegister(uint8_t address, uint8_t data)
	{
		atomic if(state == STATE_IDLE)
		{
			state = STATE_WRITING;
			regAddr = address;
			regData = data;
			
			call RearbitDelay.startOneShot(1);
			return SUCCESS;
			
		}
		else return EBUSY;
	}

	event void SPIResource.granted()
	{
		atomic if(state == STATE_READING)
		{
			result = GetRegister(regAddr);
		}
		else atomic if(state == STATE_WRITING)
		{
			result = SetRegister(regAddr, regData);	
		}
		
		if(result != SUCCESS) 
		{
			call Enable.set();
			post SignalDone();
		}
	}
	
	async event void SPI.sendDone(uint8_t *txBuf, uint8_t *rxBuf, uint16_t len, error_t error)
	{
		result = error;
		scaStat = GetScaStatus(spiRxBuf[0]);
		regData = (spiRxBuf[1]);
		
		call Enable.set();
		call SPIResource.release();
		
		post SignalDone();
	}
	
	event void RearbitDelay.fired()
	{
		if(call SPIResource.request() != SUCCESS)
		{
			call RearbitDelay.startOneShot(1);
		}
	}
}